#pragma once
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <atomic>
#include <stdexcept>
#include <sys/stat.h>
#include <cstddef>
#include <cstdlib>
#include <array>

#include "def.h"

template <typename T, size_t size>
struct FixLengthStruct{
    volatile std::atomic<size_t> next_write;
    T data[size];
    size_t _size;
    bool push(const T& value){
        auto write_pos = next_write.load();
        memcpy(data+(write_pos&(size-1)), &value, sizeof(T));
        std::atomic_thread_fence(std::memory_order_release);
        next_write.store(write_pos+1);
        return true;
    }
    bool push(){
        next_write.fetch_add(1);
        return true;
    }
    T& get_next(){
        auto write_pos = next_write.load();
        return data[write_pos&(size-1)];
    }
    void init(){
        auto is_power_of_2_func = [](size_t N){
            return ((N & (N - 1)) == 0) && (N != 0);
        };

        if(!is_power_of_2_func(size)){
            throw std::runtime_error("power of 2 error in FixLengthStruct");
        }
        next_write.store(0);
        _size = size;
    }
    T& operator[](size_t idx){
        return data[idx & (size-1)];
    }

};


struct PriceLevel {
    uint64_t price;  // 整数化价格
    double size;      // 数量
};

//价格档位的变化信息
struct PriceLevelStruct {
    uint8_t exchange;       // 交易所代码
    uint32_t market_id;     // 市场ID
    PriceLevel pl; 
    OrderSideEnum order_side; // true 表示买盘，false 表示卖盘
};

//订单信息
struct OrderStruct {
    uint8_t exchange;           // 交易所代码
    uint32_t market_id;         // 市场 ID
    OrderActionEnum order_type;   // 订单类型
    uint64_t order_id;          // 订单 ID
    OrderSideEnum order_side;       // 是否为买单
    double size;                // 订单数量
    int price;                  // 订单价格 
};

//订单回报信息
struct OrderRspStruct {
    uint8_t exchange;             // 交易所代码
    uint32_t market_id;           // 市场 ID
    uint64_t client_order_id;     // 策略本地订单 ID
    uint64_t order_id;            // 交易所订单 ID
    double size;                  // 订单数量
    int price;                    // 订单价格
    OrderSatusEnum status;        // 订单状态
    uint64_t send_timestamp;          // 发送时间戳
    uint64_t receive_timestamp;       // 接收时间戳
};

//成交信息
struct TradeStruct {
    uint8_t exchange;       // 交易所代码
    uint32_t market_id;    // 市场 ID
    uint64_t trade_id;     // 交易 ID
    double size;           // 成交数量
    int price;          // 成交价格
    uint64_t ask_id;       // 卖单 ID
    uint64_t bid_id;       // 买单 ID
    uint64_t timestamp;    // 时间戳
};

#define PRICELEVELSTRUCT_NUM  0x40000
#define ORDERSTRUCT_NUM  0x20000
#define TRADESTRUCT_NUM  0x20000
#define ORDERRSPSTRUCT_NUM  0x20000

typedef FixLengthStruct<PriceLevelStruct, PRICELEVELSTRUCT_NUM> PriceLevelShmStruct;
typedef FixLengthStruct<OrderStruct, ORDERSTRUCT_NUM> OrderShmStruct;
typedef FixLengthStruct<TradeStruct, TRADESTRUCT_NUM> TradeShmStruct;
typedef FixLengthStruct<OrderRspStruct, ORDERRSPSTRUCT_NUM> OrderRspShmStruct;

template<typename T>
bool check_struct_magic(const T &m) {
    bool ret = T::calculate_magic() == m.magic;
    if(!ret){
        std::cout<<"check magic of "<<T::name()<<" failed, "<<T::calculate_magic()<<"!="<<m.magic<<std::endl;
    }
    return ret;
}

template<typename T>
size_t calc_struct_magic() {
    return offsetof(T, magic);
}


struct MARKETStruct{
    PriceLevelShmStruct priceLevelShm;
    OrderShmStruct orderShm;
    TradeShmStruct tradeShm;
    OrderRspShmStruct orderRspShm;
    size_t magic = calculate_magic();
    static size_t calculate_magic() {
        auto m = calc_struct_magic<MARKETStruct>();
        std::cout<<"magic of "<<name()<<": "<<m<<std::endl;
        return m;
    }
    [[nodiscard]] static const char* name(){
        return "TOTStruct";
    }
    void init(){
        priceLevelShm.init();
        orderShm.init();
        tradeShm.init();
        orderRspShm.init();
        magic = calculate_magic();
    }
};



template<typename T>
T *link_shm_read_only(std::string suffix) {
//    std::string path = std::string("/dev/shm/") + T::name();
    std::string path = T::name()+suffix;
    int fd = shm_open(path.c_str(), O_RDONLY, 0);
    if (fd == -1) {
        std::cerr << "Failed to open shared memory read only " << path << std::endl;
        exit(1);
    }
    void *mem = mmap(nullptr, sizeof(T), PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);
    if (mem == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        exit(1);
    }
    auto t = reinterpret_cast<T *>(mem);
    if (!check_struct_magic(*t)) {
        std::cerr << "Failed to check magic " << path << std::endl;
        exit(1);
    }
    std::cout<<"link to shm "<<path<<", read only"<<std::endl;
    return t;
}

template<typename T>
T *link_shm_rw(std::string suffix) {
    // 拼接共享内存路径
    std::string path = T::name() + suffix;

    // ✅ 打开共享内存（可读可写）
    int fd = shm_open(path.c_str(), O_RDWR, 0);
    if (fd == -1) {
        std::cerr << "Failed to open shared memory read-write " << path << std::endl;
        exit(1);
    }

    // ✅ 映射到本地内存（读写权限）
    void *mem = mmap(nullptr, sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 0);
    if (mem == MAP_FAILED) {
        std::cerr << "Failed to map shared memory (read-write)" << std::endl;
        close(fd);
        exit(1);
    }

    // ✅ 转换为结构体指针
    auto t = reinterpret_cast<T *>(mem);

    // ✅ 验证结构体的 magic
    if (!check_struct_magic(*t)) {
        std::cerr << "Failed to check magic " << path << std::endl;
        munmap(mem, sizeof(T));
        close(fd);
        exit(1);
    }

    std::cout << "link to shm " << path << ", read-write" << std::endl;
    return t;
}

#ifndef PAGE_SIZE
#define PAGE_SIZE 128  // 如果你有自己的定义，这行可以省略
#endif

template<typename T>
class SharedMemory {
public:
    SharedMemory(const std::string& suffix_) {
        suffix = suffix_;
        auto path = get_path(suffix);
        std::cout<<"shm_open "<<path<<std::endl;
        fd_ = shm_open(path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        if (fd_ == -1) {
            std::cerr << "Failed to open shared memory object [" << strerror(errno) << "] " << path << std::endl;
            throw std::runtime_error("Failed to open file");
        }
        size_ = (sizeof(T) + (PAGE_SIZE - 1)) / PAGE_SIZE * PAGE_SIZE;
        std::cout<<"shm PAGE_SIZE "<< PAGE_SIZE <<std::endl;
        std::cout<<"shm sizeof(T) "<< sizeof(T) <<std::endl;

        std::cout<<"shm ftruncate "<<double(size_)/1024/1024/1024<<"G"<<std::endl;
        if (ftruncate(fd_, size_) == -1) {
            close(fd_);
            std::cerr << "Failed to set shared memory size [" << strerror(errno) << "] " << path << " " << size_ << std::endl;
            throw std::runtime_error("Failed to set file size");
        }

        // Map the file to memory
        std::cout<<"shm mmap"<<std::endl;
        void* ptr_void;
        ptr_void = mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd_, 0);
        if (ptr_void == MAP_FAILED) {
            close(fd_);
            std::cerr << "Failed to map shared memory [" << strerror(errno) << "] " << path << " " << size_ << std::endl;
            throw std::runtime_error("Failed to map memory");
        }
        ptr_ = reinterpret_cast<T*>(ptr_void);
        if (mlock(ptr_, size_) == -1) {
            std::cerr << "Failed to lock shared memory into RAM [" 
                          << strerror(errno) << "]" << std::endl;
        }
        ptr_->init();

        std::cout << "Succeed to map shared memory " << path << " " << size_ << std::endl;
    }

    void close_shm(){
        if(closed){
            auto path = get_path(suffix);
            std::cout << "shared memory already closed" << path << " " << size_ << std::endl;
        }
        else{
            // Unmap the memory and close the file
            munmap(ptr_, size_);
            close(fd_);
            unlink_shared_memory();
            closed = true;
        }
    }

    ~SharedMemory() {
    }

    T *get_ptr() const {
        return ptr_;
    }

private:
//    std::stirng path;
    int fd_;
    T *ptr_;
    size_t size_;
    std::string suffix;
    bool closed{false};

    static std::string get_path(const std::string& suffix_){
        return std::string(T::name())+suffix_;
    }

    void unlink_shared_memory() {
        // Unlink the shared memory file
        auto path = get_path(suffix);
        if (shm_unlink(path.c_str()) == -1) {
            std::cerr << "Failed to unlink shared memory: " << strerror(errno) << " " << path << std::endl;
        }
        else{
            std::cout<<"unlink shared memory: "<<path<<std::endl;
        }
    }
};
